import type { ComputedRef, ExtractPropTypes, PropType, Ref, VNode } from 'vue';
import type { FormItemRule, FormRules } from 'element-plus';
import type { ComponentType } from '../componentMap';
import type { OptionsItem } from './formItem';
import type { ButtonOptions } from '#/types/propTypes';
import type { Fn } from '#/types/global';

export type Recordable<T = any> = Record<string, T>;
export declare type InternalNamePath = (string | number)[];
export declare type NamePath = string | number | InternalNamePath;
export type Rule = FormRules & {
  trigger?: 'blur' | 'change' | ['change', 'blur'];
};
export type FieldMapToTime = [string, [string, string], (string | [string, string])?][];
export type DynamicProps<T> = {
  [P in keyof T]: Ref<T[P]> | T[P] | ComputedRef<T[P]>;
};

export interface UseFormValuesContext {
  defaultValueRef: Ref<any>;
  getSchema: ComputedRef<FormSchema[]>;
  getProps: ComputedRef<FormProps>;
  formModel: Recordable;
}

export interface FormProps {
  rules?: FormRules; //表单验证规则
  inline?: boolean; //	行内表单模式
  labelPosition?: 'left' | 'right' | 'top'; //表单域标签的位置
  labelWidth?: number | string; //标签的长度 作为 Form 直接子元素的 form-item 会继承该值
  labelSuffix?: string; //表单域标签的后缀
  hideRequiredAsterisk?: boolean; //是否隐藏必填字段标签旁边的红色星号
  requireAsteriskPosition?: 'left' | 'right'; //星号的位置
  showMessage?: boolean; //是否显示校验错误信息
  inlineMessage?: boolean; //是否以行内形式展示校验信息
  statusIcon?: boolean; //是否在输入框中显示校验结果反馈图标
  validateOnRuleChange?: boolean; //是否在 rules 属性改变后立即触发一次验证
  size?: 'large' | 'default' | 'small' | ''; //用于控制该表单内组件的尺寸
  disabled?: boolean; // 是否禁用该表单内的所有组件。 如果设置为 true, 它将覆盖内部组件的 disabled 属性
  scrollToError?: boolean; //当校验失败时，滚动到第一个错误表单项
  rowProps?: RowProps;
  schemas?: FormSchema[];
  mergeDynamicData?: Recordable; //额外传递到子组件的参数 values
  baseColProps?: Partial<ColEx>; //配置所有选子项的 ColProps，不需要逐个配置，子项也可单独配置优先与全局
  rulesMessageJoinLabel?: boolean; //	如果表单项有校验，会自动生成校验信息，该参数控制是否将字段中文名字拼接到自动生成的信息后方
  transformDateFunc?: (date: any) => string; //时间处理
  showAdvancedButton?: boolean; //是否显示收起展开按钮
  alwaysShowLines?: number; //折叠时始终保持显示的行数
  autoAdvancedLine?: number; //如果 showAdvancedButton 为 true，超过指定行数行默认折叠
  emptySpan?: number; // 空白行格 如一行没有铺满 剩余格数  col间隔格数/移动格数
  showActionButtonGroup?: boolean; //是否显示操作按钮
  showResetButton?: boolean; //是否显示重置按钮
  showSubmitButton?: boolean; //是否显示提交按钮
  resetButtonOptions?: Partial<ButtonOptions>; //重置按钮配置
  submitButtonOptions?: Partial<ButtonOptions>; //确认按钮配置
  submitOnReset?: boolean;
  actionColBool?: boolean; //操作按钮是否站一行
  actionClass?: string; //操作按钮class
  scrollIntoViewOptions?: Recordable | boolean; //当校验有失败结果时，滚动到第一个失败的表单项目 可通过 scrollIntoView 配置
}

export interface FormSchema<T extends ComponentType = any> {
  field: string; // 字段名
  fieldTwo?: string; //字段名二
  changeEvent?: string; //表单更新事件名称
  label: string | undefined; //标签名
  labelWidth?: string | number; //
  required?: boolean; // 是否必须
  rules?: FormItemRule[]; //验证规则
  rulesMessageJoinLabel?: boolean; //	校验信息是否加入 label
  defaultValue?: any; // 默认值
  component: ComponentType; //组件
  colProps?: Partial<ColEx>; // col参数
  dynamicRules?: (renderCallbackParams: RenderCallbackParams) => FormItemRule[]; //动态判返当前组件你校验规则
  show?: boolean | ((renderCallbackParams: RenderCallbackParams) => boolean); //动态判断当前组件是否显示，css 控制，不会删除 dom
  ifShow?: boolean | ((renderCallbackParams: RenderCallbackParams) => boolean); //动态判断当前组件是否显示，js 控制，会删除 dom
  componentProps?:
    | ((opt: {
        schema: FormSchema;
        formActionType: FormActionType;
        formModel: Recordable;
        isInit: boolean; //是否setFieldsValue过来(初始赋值)
      }) => Recordable)
    | ComponentProps
    | object; //传递到子组件数据
  colSlot?: string; //自定义 slot，渲染组件 （需要自行包含 formItem）
  slot?: string; //自定义 slot，渲染组件
  renderComponentContent?:
    | ((renderCallbackParams: RenderCallbackParams) => any)
    | VNode
    | VNode[]
    | string; //自定义渲染组内部的 slot
  renderColContent?:
    | ((renderCallbackParams: RenderCallbackParams) => any)
    | VNode
    | VNode[]
    | string; //自定义渲染组件（需要自行包含 formItem）
  render?: ((renderCallbackParams: RenderCallbackParams) => any) | VNode | VNode[] | string; //自定义渲染组件
  suffix?:
    | string
    | number
    | VNode
    | ((renderCallbackParams: RenderCallbackParams) => string | VNode | number); //组件后面的内容
  prefix?:
    | string
    | number
    | VNode
    | ((renderCallbackParams: RenderCallbackParams) => string | VNode | number); //组件前面的内容
  /**
   * 通过布局修改 组件后面的内容改为上面内容 组件前面的内容改为下面内容
   */
  colOrRow?: 'col' | 'row';
}
export interface FormActionType {
  setProps: (formProps: Partial<FormProps>) => Promise<void>;
  setFieldsValue: (values: Recordable) => Promise<void>;
  /**重置表单 注意一定要先完成后再操作其他 */
  resetFields: () => Promise<void>;
  getFieldsValue: () => Recordable;
  clearValidate: (name?: string | undefined) => Promise<void>;
  validate: (nameList?: NamePath[]) => Promise<any>;
  validateField: (name?: string | undefined) => Promise<void>;
  updateSchema: (data: Partial<FormSchemaInner> | Partial<FormSchemaInner>[]) => Promise<void>;
  appendSchemaByField: (
    schema: FormSchema | FormSchema[],
    prefixField?: string | undefined,
    first?: boolean | undefined,
  ) => Promise<void>; //插入到指定 filed 后面，如果没传指定 field，则插入到最后,当 first = true 时插入到第一个位置
  removeSchemaByField: (field: string | string[]) => Promise<void>; //根据 field 删除 Schema
}
/**
 * 自定义组件相关参数 官网组件见官网文档
 */
export interface ComponentProps {
  api?: any; //请求接口
  params?: Recordable; //请求接口参数
  resultField?: string; //接口返回值字段映射 支持 a.b.c
  disabled?: boolean; //是否禁用
  labelField?: string; //字段映射
  valueField?: string; //字段映射
  disabledField?: string; //请求接口返回数据中那个字段表示禁用
  innerOptions?: OptionsItem[]; //请求接口返回数据中添加自定义部分选项
  disabledValue?: string[] | number[]; //请求接口返回数据中禁用的值
  numberToString?: boolean; //value 是否转换字符串
  options?: OptionsItem[]; //下拉选项数据
  multiple?: boolean; //是否支持多选
  accept?: string; //上传图片 支持上传的类型
  limit?: number; //文件上传个数限制
  divClass?: string; //上传图片|InputNumberGroup  样式（大小 圆角等）
  maxSize?: number; //上传图片时大小限制
  beforeUpload?: Fn; //上传图片 上传前函数
  //树形结构字段映射
  props?: {
    children?: string;
    label?: string;
    value?: string;
  };
  /**
   * 自定义处理接口返回参数
   */
  afterFetch?: Fn;
  startMin?: number; //InputNumberGroup 开始最小值
  startMax?: number; //InputNumberGroup 开始最大值
  endMin?: number; //InputNumberGroup 结束最小值
  endMax?: number; //InputNumberGroup 结束最大值
  /** 开始结束是否关联 InputNumberGroup */
  startRelatedEnd?: boolean;
  placeholder?: string;
  height?: number;
}

export declare const rowProps: () => {
  gutter?: number;
  justify: PropType<'start' | 'end' | 'center' | 'space-around' | 'space-between' | 'space-evenly'>;
  align?: PropType<'top' | 'middle' | 'bottom'>;
  tag?: string;
};
export declare type RowProps = Partial<ExtractPropTypes<ReturnType<typeof rowProps>>>;

export interface ColEx {
  span?: number; //栅格占据的列数
  offset?: number; //栅格左侧的间隔格数
  push?: number; //栅格向右移动格数
  pull?: number; //栅格向左移动格数
  xs?: number | { span?: number; offset?: number; pull?: number; push?: number };
  sm?: number | { span?: number; offset?: number; pull?: number; push?: number };
  md?: number | { span?: number; offset?: number; pull?: number; push?: number };
  lg?: number | { span?: number; offset?: number; pull?: number; push?: number };
  xl?: number | { span?: number; offset?: number; pull?: number; push?: number };
  tag?: string;
}
export type RegisterFn = (formInstance: FormActionType) => void;
export type UseFormReturnType = [RegisterFn, FormActionType];

export interface RenderCallbackParams {
  schema: FormSchema;
  values: Recordable;
  model: Recordable;
  field: string;
}
export interface ComponentFormSchema<T extends ComponentType = any> extends FormSchema<T> {
  // render component
  component: T;
}
export interface SlotFormSchema extends FormSchema {
  // Custom slot, in form-item
  slot: string;
}
export declare type Nullable<T> = T | null;
export type FormSchemaInner = Partial<ComponentFormSchema> & Partial<SlotFormSchema> & FormSchema;
export interface AdvanceState {
  isAdvanced: boolean;
  hideAdvanceBtn: boolean;
  isLoad: boolean;
  actionSpan: number;
}
